/**
 * @file thread2.c
 * @brief TCP服务器通信线程实现
 * 
 * 该线程负责建立和维护TCP服务器，处理与客户端的通信。主要功能包括：
 * 1. 初始化并启动TCP服务器，监听指定端口(20163)
 * 2. 接受客户端连接请求并创建客户端处理线程
 * 3. 管理多个客户端连接(最多10个)
 * 4. 处理客户端数据收发
 * 5. 监听和处理系统消息队列中的消息
 * 6. 在WiFi状态变化时重启服务器
 * 
 * @note 该线程是系统与外部控制设备通信的核心，提供数据交换接口
 * 
 * @author 伞控无人机项目组
 * @date 2023
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include "thread2.h"
#include "thread1.h"
#include "msg_queue.h"

// 模块名称定义
#define THREAD2_MODULE LOG_MODULE_TCP

#define CHECK_INTERVAL 2     // 检查WiFi状态的间隔（秒）
#define TCP_PORT 20163       // TCP服务器端口
#define MAX_CLIENTS 10       // 最大客户端连接数
#define BUFFER_SIZE 1024     // 接收缓冲区大小

// 全局变量
static int g_server_socket = -1;        // 服务器套接字
static volatile int g_server_running = 0;        // 服务器运行状态
static pthread_t g_server_thread;       // 服务器线程ID
static pthread_mutex_t g_client_mutex = PTHREAD_MUTEX_INITIALIZER;  // 客户端列表互斥锁
static int g_client_count = 0;          // 客户端计数
static pthread_t g_client_threads[MAX_CLIENTS];  // 客户端线程ID数组

// 客户端连接信息结构体
typedef struct {
    int socket;                      // 客户端套接字
    struct sockaddr_in address;      // 客户端地址信息
    pthread_t thread;                // 客户端处理线程ID
    int id;                          // 客户端ID
    int active;                      // 客户端活跃状态
} client_t;

// 活跃客户端列表
static client_t *g_clients[MAX_CLIENTS] = {NULL};

// 安全发送工具函数：循环发送并避免SIGPIPE
static ssize_t safe_send_all(int sockfd, const void *buffer, size_t total_len) {
    const char *data_ptr = (const char *)buffer;
    size_t bytes_left = total_len;
    while (bytes_left > 0) {
#ifdef MSG_NOSIGNAL
        ssize_t sent = send(sockfd, data_ptr, bytes_left, MSG_NOSIGNAL);
#else
        ssize_t sent = send(sockfd, data_ptr, bytes_left, 0);
#endif
        if (sent < 0) {
            if (errno == EINTR) {
                continue;
            }
            return -1;
        }
        if (sent == 0) {
            break;
        }
        data_ptr += sent;
        bytes_left -= (size_t)sent;
    }
    return (ssize_t)(total_len - bytes_left);
}

// 注册客户端到列表
static int register_client(client_t *client) {
    pthread_mutex_lock(&g_client_mutex);
    
    // 查找空闲位置
    for (int i = 0; i < MAX_CLIENTS; i++) {
        if (g_clients[i] == NULL) {
            g_clients[i] = client;
            client->id = i;
            client->active = 1;
            g_client_count++;
            pthread_mutex_unlock(&g_client_mutex);
            return i;
        }
    }
    
    pthread_mutex_unlock(&g_client_mutex);
    return -1;  // 列表已满
}

// 从列表中移除客户端
static void unregister_client(int client_id) {
    pthread_mutex_lock(&g_client_mutex);
    
    if (client_id >= 0 && client_id < MAX_CLIENTS && g_clients[client_id] != NULL) {
        // 只是将指针置为NULL，实际的内存释放在客户端线程中处理
        g_clients[client_id] = NULL;
        g_client_count--;
    }
    
    pthread_mutex_unlock(&g_client_mutex);
}

// 关闭所有客户端连接
static void close_all_clients() {
    pthread_mutex_lock(&g_client_mutex);
    
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "正在关闭所有客户端连接，当前活跃客户端数: %d", g_client_count);
    
    for (int i = 0; i < MAX_CLIENTS; i++) {
        if (g_clients[i] != NULL) {
            client_t *client = g_clients[i];
            
            // 获取客户端信息
            char client_ip[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, &(client->address.sin_addr), client_ip, INET_ADDRSTRLEN);
            int client_port = ntohs(client->address.sin_port);
            
            LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "关闭客户端连接 ID: %d, IP: %s, 端口: %d", i, client_ip, client_port);
            
            // 关闭套接字，这会导致recv()函数返回错误
            if (client->socket >= 0) {
                shutdown(client->socket, SHUT_RDWR);
                close(client->socket);
                client->socket = -1;
            }
            
            // 标记为非活跃
            client->active = 0;
        }
    }
    
    pthread_mutex_unlock(&g_client_mutex);
    
    // 给足够的时间让客户端线程退出
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "等待所有客户端线程退出...");
    sleep(1);
}

// 客户端线程处理函数
void *client_handler(void *arg) {
    client_t *client = (client_t *)arg;
    char buffer[BUFFER_SIZE];
    ssize_t read_size = 0; // 使用ssize_t匹配recv返回类型
    
    // 获取客户端IP地址和端口
    char client_ip[INET_ADDRSTRLEN];
    inet_ntop(AF_INET, &(client->address.sin_addr), client_ip, INET_ADDRSTRLEN);
    int client_port = ntohs(client->address.sin_port);
    
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "客户端处理线程启动，客户端IP: %s, 端口: %d, ID: %d", 
             client_ip, client_port, client->id);
    
    // 向客户端发送欢迎消息
    const char *welcome_message = "欢迎连接到UD_ICM TCP服务器\n";
    (void)safe_send_all(client->socket, welcome_message, strlen(welcome_message));
    
    // 接收并处理客户端消息
    while (client->active && (read_size = recv(client->socket, buffer, BUFFER_SIZE - 1, 0)) > 0) {
        // 确保接收到的数据以NULL结尾
        buffer[read_size] = '\0';
        
        LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "从客户端(%s:%d)接收到消息: %s", 
                 client_ip, client_port, buffer);
        
        // 这里可以添加针对接收消息的处理逻辑
        
        // 回复客户端
        char reply[BUFFER_SIZE + 50];
        int n = snprintf(reply, sizeof(reply), "服务器已收到您的消息: %s", buffer);
        size_t reply_len = (n < 0) ? 0 : (size_t)((n < (int)sizeof(reply)) ? n : (int)sizeof(reply));
        (void)safe_send_all(client->socket, reply, reply_len);
    }
    
    // 客户端断开连接或发生错误
    if (read_size == 0) {
        LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "客户端(%s:%d)断开连接", client_ip, client_port);
    } else if (read_size == -1) {
        if (client->active) {
            LOG_WARN(LOG_TO_FILE, THREAD2_MODULE, "从客户端(%s:%d)接收消息失败: %s", 
                     client_ip, client_port, strerror(errno));
        } else {
            LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "客户端(%s:%d)连接被服务器主动关闭", 
                     client_ip, client_port);
        }
    }
    
    // 关闭客户端套接字
    if (client->socket >= 0) {
        close(client->socket);
        client->socket = -1;
    }
    
    // 从活跃客户端列表中移除
    unregister_client(client->id);
    
    // 释放客户端结构体内存
    free(client);
    
    return NULL;
}

// 检查端口是否可用
static int is_port_available(int port) {
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        LOG_ERROR(LOG_TO_FILE, THREAD2_MODULE, "创建套接字失败: %s", strerror(errno));
        return 0;
    }
    
    // 设置套接字选项：允许地址重用
    int opt = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        LOG_ERROR(LOG_TO_FILE, THREAD2_MODULE, "设置套接字选项失败: %s", strerror(errno));
        close(sock);
        return 0;
    }
    
    // 尝试绑定端口
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(port);
    
    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        LOG_WARN(LOG_TO_FILE, THREAD2_MODULE, "端口 %d 被占用: %s", port, strerror(errno));
        close(sock);
        return 0;
    }
    
    // 端口可用，关闭套接字
    close(sock);
    return 1;
}

// 停止TCP服务器
static void stop_tcp_server() {
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "正在尝试停止TCP服务器...");
    
    if (g_server_running && g_server_socket >= 0) {
        // 先标记服务器为非运行状态
        g_server_running = 0;
        
        // 关闭所有客户端连接
        close_all_clients();
        
        // 关闭服务器套接字，这会导致accept()函数返回错误
        LOG_DEBUG(LOG_TO_CONSOLE_ONLY, THREAD2_MODULE, "关闭服务器套接字 %d", g_server_socket);
        shutdown(g_server_socket, SHUT_RDWR);
        close(g_server_socket);
        g_server_socket = -1;
        
        // 等待服务器线程结束
        LOG_DEBUG(LOG_TO_CONSOLE_ONLY, THREAD2_MODULE, "等待服务器线程结束...");
        pthread_join(g_server_thread, NULL);
        
        LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "TCP服务器已停止");
    } else {
        LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "TCP服务器未运行，无需停止");
    }
}

// TCP服务器线程函数
void *tcp_server_thread(void *arg) {
    (void)arg;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);
    int client_sock;

    // 避免send触发SIGPIPE导致进程退出
    signal(SIGPIPE, SIG_IGN);
    
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "TCP服务器线程启动，端口: %d", TCP_PORT);
    
    // 创建服务器套接字
    g_server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (g_server_socket < 0) {
        LOG_ERROR(LOG_TO_FILE, THREAD2_MODULE, "创建服务器套接字失败: %s", strerror(errno));
        g_server_running = 0;
        return NULL;
    }
    
    LOG_DEBUG(LOG_TO_CONSOLE_ONLY, THREAD2_MODULE, "创建服务器套接字成功，套接字ID: %d", g_server_socket);
    
    // 设置套接字选项：允许地址重用
    int opt = 1;
    if (setsockopt(g_server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        LOG_ERROR(LOG_TO_FILE, THREAD2_MODULE, "设置套接字选项失败: %s", strerror(errno));
        close(g_server_socket);
        g_server_socket = -1;
        g_server_running = 0;
        return NULL;
    }
    
    // 配置服务器地址
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;  // 监听所有网络接口
    server_addr.sin_port = htons(TCP_PORT);
    
    // 绑定端口
    if (bind(g_server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        LOG_ERROR(LOG_TO_FILE, THREAD2_MODULE, "绑定端口失败: %s", strerror(errno));
        close(g_server_socket);
        g_server_socket = -1;
        g_server_running = 0;
        return NULL;
    }
    
    // 开始监听
    if (listen(g_server_socket, MAX_CLIENTS) < 0) {
        LOG_ERROR(LOG_TO_FILE, THREAD2_MODULE, "监听失败: %s", strerror(errno));
        close(g_server_socket);
        g_server_socket = -1;
        g_server_running = 0;
        return NULL;
    }
    
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "TCP服务器已启动，监听端口: %d，等待客户端连接...", TCP_PORT);
    
    // 循环接受客户端连接请求
    while (g_server_running) {
        LOG_DEBUG(LOG_TO_CONSOLE_ONLY, THREAD2_MODULE, "等待新的客户端连接...");
        
        // 在每次accept前重置client_len
        client_len = sizeof(client_addr);
        
        // 接受客户端连接
        client_sock = accept(g_server_socket, (struct sockaddr *)&client_addr, &client_len);
        if (client_sock < 0) {
            if (g_server_running) {
                LOG_ERROR(LOG_TO_FILE, THREAD2_MODULE, "接受客户端连接失败: %s", strerror(errno));
            } else {
                LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "服务器已停止运行，退出accept循环");
                break;
            }
            continue;  // 继续等待下一个连接
        }
        
        // 为新客户端创建客户端结构体
        client_t *client = (client_t *)malloc(sizeof(client_t));
        if (!client) {
            LOG_ERROR(LOG_TO_FILE, THREAD2_MODULE, "内存分配失败，无法处理新客户端连接");
            close(client_sock);
            continue;
        }
        
        // 初始化客户端结构体
        memset(client, 0, sizeof(client_t));  // 确保结构体清零
        client->socket = client_sock;
        memcpy(&(client->address), &client_addr, sizeof(client_addr));
        client->active = 1;  // 初始化为活跃状态
        
        // 获取客户端IP地址和端口
        char client_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN);
        int client_port = ntohs(client_addr.sin_port);
        
        LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "新客户端连接，IP: %s, 端口: %d", client_ip, client_port);
        
        // 注册客户端
        int client_id = register_client(client);
        if (client_id < 0) {
            LOG_WARN(LOG_TO_FILE, THREAD2_MODULE, "客户端注册失败，已达最大连接数");
            free(client);
            close(client_sock);
            continue;
        }
        
        // 创建新线程处理客户端连接
        if (pthread_create(&(client->thread), NULL, client_handler, (void *)client) != 0) {
            LOG_ERROR(LOG_TO_FILE, THREAD2_MODULE, "创建客户端处理线程失败: %s", strerror(errno));
            unregister_client(client_id);
            free(client);
            close(client_sock);
            continue;
        }
        
        // 保存线程ID
        g_client_threads[client_id] = client->thread;
        
        // 设置线程为分离状态，线程结束后自动释放资源
        pthread_detach(client->thread);
    }
    
    // 服务器停止运行，关闭套接字
    if (g_server_socket >= 0) {
        LOG_DEBUG(LOG_TO_CONSOLE_ONLY, THREAD2_MODULE, "关闭服务器套接字 %d", g_server_socket);
        close(g_server_socket);
        g_server_socket = -1;
    }
    
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "TCP服务器线程结束");
    return NULL;
}

// 启动TCP服务器
static int start_tcp_server() {
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "尝试启动TCP服务器...");
    
    // 检查服务器是否已在运行
    if (g_server_running) {
        LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "TCP服务器已在运行，先停止它");
        stop_tcp_server();
        sleep(1);
    }
    
    // 检查端口是否可用
    while (!is_port_available(TCP_PORT)) {
        LOG_WARN(LOG_TO_FILE, THREAD2_MODULE, "端口 %d 不可用，等待端口释放...", TCP_PORT);
        sleep(5);  // 等待5秒后重试
    }
    
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "端口 %d 可用，正在启动TCP服务器...", TCP_PORT);
    
    // 设置服务器为运行状态
    g_server_running = 1;
    
    // 创建服务器线程
    if (pthread_create(&g_server_thread, NULL, tcp_server_thread, NULL) != 0) {
        LOG_ERROR(LOG_TO_FILE, THREAD2_MODULE, "创建TCP服务器线程失败: %s", strerror(errno));
        g_server_running = 0;
        return -1;
    }
    
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "TCP服务器启动成功，线程ID: %lu", (unsigned long)g_server_thread);
    return 0;
}

// 清空指定类型的所有消息
static void clear_all_messages(int queue_id, long msg_type) {
    struct msg_data msg;
    int ret;
    int count = 0;
    
    LOG_DEBUG(LOG_TO_CONSOLE_ONLY, THREAD2_MODULE, "清空消息队列中的消息类型 %ld...", msg_type);
    
    // 循环接收消息直到队列为空
    while (1) {
        ret = recv_msg(queue_id, msg_type, &msg, 0);
        if (ret <= 0) {
            break;  // 没有更多消息或发生错误
        }
        LOG_DEBUG(LOG_TO_CONSOLE_ONLY, THREAD2_MODULE, "已清理消息：%s", msg.msg_text);
        count++;
    }
    
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "共清空了 %d 条消息", count);
}

// 检查并处理消息队列中的消息
static void process_messages() {
    struct msg_data msg;
    int msg_len;
    
    LOG_DEBUG(LOG_TO_CONSOLE_ONLY, THREAD2_MODULE, "检查消息队列 %d 中的 MSG_TYPE_WIFI_RESET 消息...", g_msg_queue_id);
    
    // 非阻塞方式尝试接收消息
    memset(&msg, 0, sizeof(msg));
    msg_len = recv_msg(g_msg_queue_id, MSG_TYPE_WIFI_RESET, &msg, 0);
    
    // 如果接收到消息
    if (msg_len > 0) {
        LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "接收到WiFi热点重置消息：%s", msg.msg_text);
        
        // 热点重置后，需要重启TCP服务器
        LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "收到热点重置消息，重启TCP服务器...");
        
        // 确保停止所有当前运行的TCP服务器和客户端连接
        if (g_server_running) {
            LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "TCP服务器正在运行，先停止它");
            stop_tcp_server();
            sleep(2);  // 确保完全停止
        } else {
            LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "TCP服务器未运行，直接启动新服务器");
        }
        
        // 启动新的TCP服务器
        start_tcp_server();
        
        // 清空所有剩余的WiFi重置消息，避免重复处理
        //clear_all_messages(g_msg_queue_id, MSG_TYPE_WIFI_RESET);
    } else {
        LOG_DEBUG(LOG_TO_CONSOLE_ONLY, THREAD2_MODULE, "没有检测到WiFi重置消息");
    }
}

// 线程2函数实现 - WiFi热点状态监控和消息处理
void *thread2_function(void *arg) {
    LOG_INFO(LOG_TO_FILE, LOG_MODULE_TCP, "线程2启动: TCP服务器");
    (void)arg;
    int prev_wifi_status = WIFI_HOTSPOT_FAILURE;
    
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "WiFi热点状态监控和消息处理线程启动");
    LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "初始WiFi热点状态: %s", 
            g_wifi_hotspot_status == WIFI_HOTSPOT_SUCCESS ? "成功" : "失败");
    
    // 启动时清空所有旧消息
    clear_all_messages(g_msg_queue_id, MSG_TYPE_WIFI_RESET);
    
    // 主循环：监控WiFi热点状态
    while (1) {
        // 检查WiFi热点状态
        if (g_wifi_hotspot_status == WIFI_HOTSPOT_SUCCESS) {
            // 如果状态从失败变为成功
            if (prev_wifi_status != WIFI_HOTSPOT_SUCCESS) {
                LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "检测到WiFi热点状态变为成功");
                prev_wifi_status = WIFI_HOTSPOT_SUCCESS;
                
                // 确保TCP服务器已停止，然后启动新的服务器
                LOG_INFO(LOG_TO_FILE, THREAD2_MODULE, "热点重新变为成功状态，确保服务器停止后启动新服务器");
            }

            // 在WiFi成功状态下每轮轮询一次消息，避免错过重置消息
            process_messages();
        } else {
            // 如果状态从成功变为失败
            if (prev_wifi_status != WIFI_HOTSPOT_FAILURE) {
                LOG_WARN(LOG_TO_FILE, THREAD2_MODULE, "检测到WiFi热点状态变为失败");
                prev_wifi_status = WIFI_HOTSPOT_FAILURE;
                
                // 立即停止TCP服务器
                LOG_WARN(LOG_TO_FILE, THREAD2_MODULE, "WiFi热点失效，立即停止TCP服务器和所有客户端连接");
                stop_tcp_server();
            }
        }
        
        // 休眠指定时间
        sleep(CHECK_INTERVAL);
    }
    
    return NULL;
} 